package org.lc.oauth.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.annotation.Resource;
import org.lc.oauth.dto.RegisteredClientDto;
import org.lc.oauth.extension.password.PasswordAuthenticationToken;
import org.lc.oauth.service.Oauth2Service;
import org.lc.oauth.vo.LcUserDetails;
import org.lc.platform.base.constant.AuthConstant;
import org.lc.platform.base.domain.JwtUser;
import org.lc.platform.base.exception.BusinessException;
import org.lc.platform.base.result.Result;
import org.lc.platform.oauth2.properties.SecurityOauth2Properties;
import org.lc.platform.redis.service.CacheService;
import org.lc.service.system.client.feign.IUserFeign;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

@Service
public class Oauth2ServiceImpl implements Oauth2Service {
    private final AtomicReference<String> updateClientSecretSql = new AtomicReference<>("UPDATE oauth2_registered_client SET client_secret = ? WHERE id = ?");
    @Resource
    private JdbcRegisteredClientRepository registeredClientRepository;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private JdbcOperations jdbcOperations;
    @Resource
    private SecurityOauth2Properties authProperties;
    @Resource
    private CacheService cacheService;

    @Resource
    private IUserFeign iUserFeign;

    @Override
    public Result<String> registeredClient(RegisteredClientDto client) {
        var registeredMallAdminClient = registeredClientRepository.findByClientId(client.getClientId());
        if (registeredMallAdminClient != null) {
            throw new BusinessException("当前客户端已存在，请重新填写");
        }

        var registeredClient = RegisteredClient
                .withId(UUID.randomUUID().toString())
                .clientId(client.getClientId())
                .clientName(client.getClientName())
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                .authorizationGrantType(PasswordAuthenticationToken.PASSWORD) // 密码模式
                .scope("all")
                .redirectUri("http://127.0.0.1:8080/authorized")
                .tokenSettings(
                        TokenSettings
                                .builder()
                                /* access_token 过期时间 */
                                .accessTokenTimeToLive(Duration.ofSeconds(authProperties.getExp()))
                                /* refresh_token 过期时间 */
                                .refreshTokenTimeToLive(Duration.ofSeconds(authProperties.getRefreshExp()))
                                .build()
                )
                .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build());

        registeredClientRepository.save(registeredClient.build());
        return Result.data("客户端添加成功");
    }

    @Override
    public Result<String> getClientSecret(String clientId) {
        if (StrUtil.isEmpty(clientId)) {
            throw new BusinessException("缺少参数客户端ID");
        }
        RegisteredClient registeredMallAdminClient = registeredClientRepository.findByClientId(clientId);
        if (registeredMallAdminClient == null || registeredMallAdminClient.getId() == null) {
            throw new BusinessException("当前客户端不存在");
        }
        String clientSecret = UUID.randomUUID(false).toString();
        String encodeSecret = passwordEncoder.encode(clientSecret);
        jdbcOperations.update(updateClientSecretSql.get(), encodeSecret, registeredMallAdminClient.getId());
        return Result.data(clientSecret);
    }

    @Override
    public boolean logout(String userId) {
        /* TODO 此处可删除用户别的相关缓存 */
        if (ObjUtil.isNotNull(userId)) {
            /* 清除相关缓存 */
            var key = userId + ":jwt_token";
            cacheService.remove(key);
            var apisKey = userId + ":apis";
            cacheService.remove(apisKey);
            var aclsKey = userId + ":acls";
            cacheService.remove(aclsKey);
            /* 清理登录状态*/
            iUserFeign.setOnlineByUserId(userId, false);
        }
        return true;
    }

    @Override
    public boolean isLoginIn(JwtUser user) {
        return false;
    }
}
